﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using Newtonsoft.Json.Linq;
using System.Linq;

#if netcoreapp
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
#endif
namespace CNative.Utilities
{
    public class ConfigurationHelper
    {
        /// <summary>
        /// 配置内容
        /// </summary>
        private static NameValueCollection _configurationCollection = new NameValueCollection();
        private static Dictionary<string, ConnectionStringSetting> _connectionStringsCollection = new Dictionary<string, ConnectionStringSetting>(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// 配置监听响应链堆栈
        /// </summary>
        private static Stack<KeyValuePair<string, FileSystemWatcher>> FileListeners = new Stack<KeyValuePair<string, FileSystemWatcher>>();

        /// <summary>
        /// 默认路径
        /// </summary>
        private static string _defaultPath = System.IO.Path.Combine(ProcessDirectory, "appsettings.json");//Directory.GetCurrentDirectory()
        public static string ProcessDirectory
        {
            get
            {
#if netcoreapp
                return AppContext.BaseDirectory;
#else
                return AppDomain.CurrentDomain.BaseDirectory;
#endif
            }
        }
        /// <summary>
        /// 最终配置文件路径
        /// </summary>
        private static string _configPath = null;

        /// <summary>
        /// 配置节点关键字
        /// </summary>
        private static string _configSection = "AppSettings";
        /// <summary>
        /// 配置节点关键字
        /// </summary>
        private static string _connectionStringsSection = "connectionStrings";

        /// <summary>
        /// 配置外连接的后缀
        /// </summary>
        private static string _configUrlPostfix = "Url";

        /// <summary>
        /// 最终修改时间戳
        /// </summary>
        private static long _timeStamp = 0L;

        private static NameValueCollection _configuration = null;
        public static NameValueCollection Configuration
        {
            get
            {
                if (_configuration == null)
                {
                    SetConfigPath();
                }
                return _configuration;
            }
        }
        /// <summary>
        /// 配置外链关键词，例如：AppSettings.Url
        /// </summary>
        //private static string _configUrlSection { get { return _configSection + "." + _configUrlPostfix; } }


        static ConfigurationHelper()
        {
            try
            {
                if (NlogHelper.IsDebugEnabled)
                    NlogHelper.Debug("ConfigurationHelper.SetConfigPath");

                SetConfigPath();
                //LoadConfiguration();
            }
            catch (Exception ex) {
                NlogHelper.Error(ex, "ConfigurationHelper()");
            }
        }

        /// <summary>
        /// 确定配置文件路径
        /// </summary>
        public static void SetConfigPath(string path = "")
        {
            if (path.IsNullOrEmpty()) path = _defaultPath;
            _configPath = path;
            //FileInfo config_info = new FileInfo(_configPath);
            //if (!config_info.Exists) return;

            //FileListeners.Push(CreateListener(config_info));
            //s_ConfigJson = LoadJsonFile(_configPath);

            //if (s_ConfigJson == null) return;// || config_json[_configSection] == null

            LoadConfiguration();
        }


#if netcoreapp

        private static IConfiguration s_ConfigJson = null;
        public static IConfiguration ConfigurationRoot
        {
            get
            {
                if (s_ConfigJson == null)
                {
                    SetConfigPath();
                }
                return s_ConfigJson;
            }
        }

        public static IConfigurationSection GetSection(string name)
        {
            JObject ret = new JObject();
            if (name.IsNullOrEmpty() || s_ConfigJson.IsNullOrEmpty()) return null;

            return s_ConfigJson.GetSection(name);
        }

        /// <summary>
        /// 读取配置文件内容
        /// </summary>
        private static void LoadConfiguration()
        {
            NlogHelper.Info("LoadConfiguration begin configPath=" + _configPath);
            //if (!System.IO.File.Exists(_configPath))
            //{
            //    LoggingHelper.Info("Not Exists configPath=" + _configPath);
            //    return;
            //}
            s_ConfigJson = LoadJsonFile(_configPath);
            if (s_ConfigJson == null)
            {
                NlogHelper.Info(" s_ConfigJson == null ");
                return;
            }
            //--------------------------------------------------------------
            _configuration = new NameValueCollection();
            foreach (var prop in s_ConfigJson.GetChildren())
            {
                if (prop.Value.IsNotNullOrEmpty())
                    _configuration[prop.Key] = prop.Value;//.ToString();
            }
            //LoggingHelper.Info("AppSettings=" + _configuration.Count);
            //--------------------------------------------------------------
            var configSteps = s_ConfigJson.GetSection(_configSection);
            foreach (var prop in configSteps.GetChildren())
            {
                if (prop.Value.IsNotNullOrEmpty())
                    _configuration[prop.Key] = prop.Value;//.ToString();
            }
            _configurationCollection = _configuration;
            //if(LoggingHelper.IsDebugEnabled)
            NlogHelper.Info("AppSettings Count=" + _configuration.Count);
            //--------------------------------------------------------------
            var cconnectionStringsCollection = new Dictionary<string, ConnectionStringSetting>(StringComparer.OrdinalIgnoreCase);
            //var list = config_object["connectionStrings"].to
            var procSteps = s_ConfigJson.GetSection(_connectionStringsSection);
            foreach (var prop in procSteps.GetChildren())
            {
                var csst = prop.Get<ConnectionStringSetting>();
                if (csst != null && csst.Name.IsNotNullOrEmpty())
                {
                    cconnectionStringsCollection[csst.Name] = csst;
                    //LoggingHelper.Info($"{ csst.Name} = {csst.ConnectionString}  {csst.ProviderName}");
                }
                //cconnectionStringsCollection[prop["name"].NullToStr()] = new ConnectionStringSetting(prop["name"].NullToStr(), prop["connectionString"].NullToStr(), prop["providerName"].NullToStr());
            }
            _connectionStringsCollection = cconnectionStringsCollection;
            //if (LoggingHelper.IsDebugEnabled)
            NlogHelper.Info("cconnectionStringsCollection=" + cconnectionStringsCollection.Count);

            NlogHelper.Info("LoadConfiguration end ");
        }

        /// <summary>
        /// 解析Json文件
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns></returns>
        private static IConfiguration LoadJsonFile(string FilePath)
        {
            //#if !DEBUG
            s_ConfigJson = new ConfigurationBuilder()
                .SetBasePath(ProcessDirectory)
                .AddJsonFile(FilePath, optional: false, reloadOnChange: true)
                .Build();
            //#else
            //configuration = new ConfigurationBuilder()
            //  .SetBasePath(ProcessDirectory)
            //  .AddJsonFile("appsettings.Development.json", optional: false, reloadOnChange: true)
            //  .Build();
            //#endif
            return s_ConfigJson;
        }
        /// <summary>
        /// GetAppSettings
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultVal"></param>
        /// <returns></returns>
        public static string GetAppSettings(string key, string defaultVal = "")
        {
            try
            {
                var tem = s_ConfigJson[key];
                if (string.IsNullOrEmpty(tem))
                    return defaultVal;
                return tem.Trim();
            }
            catch { return defaultVal; }
        }
        public static T GetAppSettings<T>(string key, T defaultVal)
        {
            try
            {
                var tem = s_ConfigJson.GetValue<T>(key);
                if (tem.IsNullOrEmpty())
                    return defaultVal;
                return tem;
            }
            catch { return defaultVal; }
        }
#else
        private static JObject s_ConfigJson = null;
        public static JObject ConfigurationRoot
        {
            get
            {
                if (s_ConfigJson == null)
                {
                    SetConfigPath();
                }
                return s_ConfigJson;
            }
        }

        public static JToken GetSection(string name)
        {
            JObject ret = new JObject();
            if (name.IsNullOrEmpty()) return ret;
            var names = name.Split(new char[] { ';' },StringSplitOptions.RemoveEmptyEntries);
            var temp = ConfigurationRoot;
            foreach (var key in names)
            {
                if (ConfigurationRoot != null && ConfigurationRoot.ContainsKey(key))
                    return ConfigurationRoot[key];
            }
            return temp;
        }

        /// <summary>
        /// 读取配置文件内容
        /// </summary>
        private static void LoadConfiguration()
        {
            if (!System.IO.File.Exists(_configPath)) return;
            var configColltion = new NameValueCollection();
            s_ConfigJson = LoadJsonFile(_configPath);
            if (s_ConfigJson == null || !(s_ConfigJson is JObject)) return;
            //--------------------------------------------------------------
            _configuration = new NameValueCollection();
            foreach (var prop in s_ConfigJson)
            {
                _configuration[prop.Key] = prop.Value.ToString();
            }
            //--------------------------------------------------------------
            if (s_ConfigJson[_configSection] != null)
            {
                foreach (JProperty prop in s_ConfigJson[_configSection])
                {
                    configColltion[prop.Name] = prop.Value.ToString();
                }
            }
            _configurationCollection = configColltion;
            //if(LoggingHelper.IsDebugEnabled)
            //LoggingHelper.Debug("_configurationCollection="+ _configurationCollection.Count);
            //--------------------------------------------------------------
            var cconnectionStringsCollection = new Dictionary<string, ConnectionStringSetting>(StringComparer.OrdinalIgnoreCase);
            if (s_ConfigJson[_connectionStringsSection] != null)
            {
                //var list = config_object["connectionStrings"].to
                foreach (JObject prop in s_ConfigJson[_connectionStringsSection])
                {
                    var csst = prop.ToObject<ConnectionStringSetting>();
                    if (csst != null && csst.Name.IsNotNullOrEmpty())
                        cconnectionStringsCollection[csst.Name] = csst;
                   //cconnectionStringsCollection[prop["name"].NullToStr()] = new ConnectionStringSetting(prop["name"].NullToStr(), prop["connectionString"].NullToStr(), prop["providerName"].NullToStr());
                }
            }
            _connectionStringsCollection = cconnectionStringsCollection;
            //if (LoggingHelper.IsDebugEnabled)
            //    LoggingHelper.Debug("_configurationCollection=" + _configurationCollection.Count);
            if (NlogHelper.IsDebugEnabled)
                NlogHelper.Debug("LoadConfiguration end " + s_ConfigJson?.ToJson());
        }

        /// <summary>
        /// 解析Json文件
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns></returns>
        private static JObject LoadJsonFile(string FilePath)
        {
            JObject config_object = null;
            try
            {
                StreamReader sr = new StreamReader(FilePath, Encoding.UTF8);
                config_object = JObject.Parse(sr.ReadToEnd());
                sr.Close();
            }
            catch (Exception ex) { NlogHelper.Error(ex, "LoadJsonFile"); }
            return config_object;
        }

         /// <summary>
        /// GetAppSettings
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultVal"></param>
        /// <returns></returns>
        public static string GetAppSettings(string key, string defaultVal = "")
        {
            try
            {
                var tem = Configuration[key];
                if (string.IsNullOrEmpty(tem))
                    return defaultVal;
                return tem.Trim();
            }
            catch { return defaultVal; }
        }
        public static T GetAppSettings<T>(string key, T defaultVal)
        {
            try
            {
                var tem = Configuration[key];
                if (tem.IsNullOrEmpty())
                    return defaultVal;
                return tem.ChangeType<T>();
            }
            catch { return defaultVal; }
        }
#endif
        /// <summary>
        /// 添加监听树节点
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        //private static KeyValuePair<string, FileSystemWatcher> CreateListener(FileInfo info)
        //{

        //    FileSystemWatcher watcher = new FileSystemWatcher();
        //    watcher.BeginInit();
        //    watcher.Path = info.DirectoryName;
        //    watcher.Filter = info.Name;
        //    watcher.IncludeSubdirectories = false;
        //    watcher.EnableRaisingEvents = true;
        //    watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size;
        //    watcher.Changed += new FileSystemEventHandler(ConfigChangeListener);
        //    watcher.EndInit();

        //    return new KeyValuePair<string, FileSystemWatcher>(info.FullName, watcher);

        //}

        private static void ConfigChangeListener(object sender, FileSystemEventArgs e)
        {
            long time = TimeStamp();
            lock (FileListeners)
            {
                if (time > _timeStamp)
                {
                    _timeStamp = time;
                    if (e.FullPath != _configPath || e.FullPath == _defaultPath)
                    {
                        while (FileListeners.Count > 0)
                        {
                            var listener = FileListeners.Pop();
                            listener.Value.Dispose();
                            if (listener.Key == e.FullPath) break;
                        }
                        SetConfigPath(e.FullPath);
                    }
                    else
                    {
                        LoadConfiguration();
                    }
                }
            }
        }

        private static long TimeStamp()
        {
            return (long)((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds * 100);
        }

        private static string c_configSection = null;
        public static string ConfigSection
        {
            get { return _configSection; }
            set { c_configSection = value; }
        }


        private static string c_configUrlPostfix = null;
        public static string ConfigUrlPostfix
        {
            get { return _configUrlPostfix; }
            set { c_configUrlPostfix = value; }
        }

        private static string c_defaultPath = null;
        public static string DefaultPath
        {
            get { return _defaultPath; }
            set { c_defaultPath = value; }
        }

        public static NameValueCollection AppSettings
        {
            get
            {
                if (_configurationCollection == null)
                {
                    SetConfigPath();
                }
                return _configurationCollection;
            }
        }
        public static Dictionary<string, ConnectionStringSetting> ConnectionStrings
        {
            get
            {
                if (_connectionStringsCollection == null)
                {
                    SetConfigPath();
                }
                return _connectionStringsCollection;
            }
        }
        public static void SetConnectionString(string name, string connectionString, string providerName)
        {
            if (name.IsNullOrEmpty() || connectionString.IsNullOrEmpty() || providerName.IsNullOrEmpty())
                return;
            if (_connectionStringsCollection == null)
                _connectionStringsCollection = new Dictionary<string, ConnectionStringSetting>(StringComparer.OrdinalIgnoreCase);
            _connectionStringsCollection[name] = new ConnectionStringSetting(name, connectionString, providerName);
        }
        /// <summary>
        /// 手动刷新配置，修改配置后，请手动调用此方法，以便更新配置参数
        /// </summary>
        public static void RefreshConfiguration()
        {
            lock (FileListeners)
            {
                //修改配置
                if (c_configSection != null) { _configSection = c_configSection; c_configSection = null; }
                if (c_configUrlPostfix != null) { _configUrlPostfix = c_configUrlPostfix; c_configUrlPostfix = null; }
                if (c_defaultPath != null) { _defaultPath = c_defaultPath; c_defaultPath = null; }
                //释放掉全部监听响应链
                while (FileListeners.Count > 0)
                    FileListeners.Pop().Value.Dispose();
                SetConfigPath(_defaultPath);
            }
        }

    }

    #region ConnectionStringSetting
    /// <summary>
    /// 表示连接字符串配置文件节中的单个命名连接字符串。
    /// </summary>
    public sealed class ConnectionStringSetting
    {
      
        public ConnectionStringSetting() { }
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name">连接字符串名称</param>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="providerName">数据库提供者类名称</param>
        public ConnectionStringSetting(string name, string connectionString, string providerName)
        {
            Name = name;
            ConnectionString = connectionString;
            ProviderName = providerName;
        }

        /// <summary>
        /// 连接字符串
        /// </summary>
        public string ConnectionString { get; set; }
        /// <summary>
        /// 连接字符串名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 数据库提供者名称 或 数据库提供者类名称
        /// </summary>
        public string ProviderName { get; set; }

        /// <summary>
        /// 是否启用主从分离模式
        /// </summary>
        public bool IsUseMasterSlaveSeparation { get; set; } = false;
        /// <summary>
        /// 从数据库连接字符串集合
        /// </summary>
        public List<string> SlaveConnectStrings { set; get; }
        public int? CommandTimeout { get; set; }
    }
    #endregion
}
